package com.wingice.system.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wingice.spring.security.common.utils.SecurityUtils;
import com.wingice.spring.security.model.KnifeUser;
import com.wingice.system.constant.SecurityConstant;
import com.wingice.system.entity.SysResource;
import com.wingice.system.entity.SysRole;
import com.wingice.system.entity.SysRoleResource;
import com.wingice.system.entity.SysRoleUser;
import com.wingice.system.mapper.SysResourceMapper;
import com.wingice.system.service.SysResourceService;
import com.wingice.system.service.SysRoleResourceService;
import com.wingice.system.service.SysRoleService;
import com.wingice.system.service.SysRoleUserService;
import com.wingice.system.vo.SysResourceView;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源信息 服务实现类
 * </p>
 *
 * @author 胡昊
 * @since 2020-07-23
 */
@Transactional
@Service
public class SysResourceServiceImpl extends ServiceImpl<SysResourceMapper, SysResource> implements SysResourceService {

    @Resource
    private SysRoleResourceService sysRoleResourceService;
    @Resource
    private SysRoleUserService sysRoleUserService;
    @Resource
    private SysRoleService sysRoleService;

    @Override
    public Boolean deleteBatch(List<String> idList) {
        final List<SysResource> sysResourceList = listChildResource(idList);
        //删除资源
        if(!CollectionUtils.isEmpty(sysResourceList)){
            //删除资源与角色关联
            sysRoleResourceService.remove(Wrappers.<SysRoleResource>lambdaQuery().in(SysRoleResource::getResourceId, sysResourceList.stream().map(SysResource::getId).collect(Collectors.toList())));
            removeByIds(sysResourceList.stream().map(SysResource::getId).collect(Collectors.toList()));
        }
        return true;
    }

    @Override
    public List<SysResourceView> treeSysResource() {
        //获取当前用户有权限的资源
        final KnifeUser knifeUser = SecurityUtils.getUser();
        final List<SysRole> userRoleList = sysRoleUserService.listUserRole(knifeUser.getId());
        if (CollectionUtils.isEmpty(userRoleList)) {
            return Collections.emptyList();
        }
        final SysRole superAdminRole = sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleKey, SecurityConstant.KNIFE_SUPER_ADMIN));
        List<SysResource> sysResourceList;
        if (userRoleList.contains(superAdminRole)) {
            sysResourceList = list();
        } else {
            final List<SysRoleResource> roleResourceList = sysRoleResourceService.list(Wrappers.<SysRoleResource>lambdaQuery().in(SysRoleResource::getRoleId, userRoleList.stream().map(SysRole::getId).collect(Collectors.toList())));
            sysResourceList = listByIds(roleResourceList.stream().map(SysRoleResource::getResourceId).collect(Collectors.toList()));
        }
        return buildResourceTree(sysResourceList);
    }

    @Override
    public List<SysResourceView> userTreeSysResource() {
        final KnifeUser knifeUser = (KnifeUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        final List<String> roleIdList = sysRoleUserService.list(Wrappers.<SysRoleUser>lambdaQuery().in(SysRoleUser::getUserId, knifeUser.getId()))
                .stream()
                .map(SysRoleUser::getRoleId)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(roleIdList)) {
            final List<String> resourceIdList = sysRoleResourceService.list(Wrappers.<SysRoleResource>lambdaQuery().in(SysRoleResource::getRoleId, roleIdList))
                    .stream()
                    .map(SysRoleResource::getResourceId)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(resourceIdList)) {
                return buildResourceTree(listByIds(resourceIdList));
            }
        }
        return Collections.emptyList();
    }

    private List<SysResourceView> buildResourceTree(List<SysResource> sysResourceList) {
        final List<SysResourceView> sysResourceViewList = sysResourceList
                .stream()
                .filter(sysResource -> sysResource.getParentId().equals("0"))
                .sorted(Comparator.comparingLong(SysResource::getWeight).reversed())
                .map(sysResource -> {
                    final SysResourceView sysResourceView = new SysResourceView();
                    BeanUtils.copyProperties(sysResource, sysResourceView);
                    return sysResourceView;
                })
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(sysResourceViewList)) {
            treeChildSysResource(sysResourceViewList, sysResourceList);
        }
        return sysResourceViewList;
    }

    private void treeChildSysResource(List<SysResourceView> sysResourceViewList, List<SysResource> allSysResourceList) {
        sysResourceViewList.forEach(sysResourceView -> {
            final List<SysResourceView> childSysResourceViewList = allSysResourceList
                    .stream()
                    .filter(sysResource -> sysResource.getParentId().equals(sysResourceView.getId()))
                    .sorted(Comparator.comparingLong(SysResource::getWeight).reversed())
                    .map(sysResource -> {
                        final SysResourceView childSysResourceView = new SysResourceView();
                        BeanUtils.copyProperties(sysResource, childSysResourceView);
                        childSysResourceView.setParentName(sysResourceView.getName());
                        return childSysResourceView;
                    })
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(childSysResourceViewList)) {
                sysResourceView.setChildren(childSysResourceViewList);
                treeChildSysResource(childSysResourceViewList, allSysResourceList);
            }
        });
    }

    private List<SysResource> listChildResource(List<String> idList) {
        final List<SysResource> result = new ArrayList<>();
        final List<SysResource> sysResourceList = listByIds(idList);
        if (!CollectionUtils.isEmpty(sysResourceList)) {
            result.addAll(sysResourceList);
        }
        final List<SysResource> sysChildrenResourceList = list(Wrappers.<SysResource>lambdaQuery().in(SysResource::getParentId, idList).orderByDesc(SysResource::getWeight));
        if (!CollectionUtils.isEmpty(sysChildrenResourceList)) {
            listChildResource(sysChildrenResourceList, result);
        }
        return result;
    }

    private List<SysResource> listChildResource(String id) {
        final List<SysResource> result = new ArrayList<>();
        final SysResource sysResource = getById(id);
        if (sysResource != null) {
            result.add(sysResource);
        }
        final List<SysResource> sysResourceList = list(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getParentId, id).orderByDesc(SysResource::getWeight));
        if (!CollectionUtils.isEmpty(sysResourceList)) {
            listChildResource(sysResourceList, result);
        }
        return result;
    }

    private void listChildResource(List<SysResource> sysResourceList, List<SysResource> result) {
        result.addAll(sysResourceList);
        final List<SysResource> childSysResourceList = list(Wrappers.<SysResource>lambdaQuery().in(SysResource::getParentId, sysResourceList.stream().map(SysResource::getId).collect(Collectors.toList())).orderByDesc(SysResource::getWeight));
        if (!CollectionUtils.isEmpty(childSysResourceList)) {
            listChildResource(childSysResourceList, result);
        }
    }
}
